package org.jsola.contract.service.impl;

import org.jsola.common.SafeKit;
import org.jsola.common.StrKit;
import org.jsola.contract.constant.ContractConstants;
import org.jsola.contract.dao.IContractDAO;
import org.jsola.contract.dao.IPartySignDAO;
import org.jsola.contract.dto.PartySignAddDTO;
import org.jsola.contract.dto.PartySignUpdateDTO;
import org.jsola.contract.entity.AppendixDO;
import org.jsola.contract.entity.ContractDO;
import org.jsola.contract.entity.PartySignDO;
import org.jsola.contract.query.PartySignQuery;
import org.jsola.contract.service.IContractService;
import org.jsola.contract.service.IPartySignService;
import org.jsola.contract.vo.PartySignAccountVO;
import org.jsola.contract.vo.PartySignListVO;
import org.jsola.contract.vo.PartySignVO;
import org.jsola.core.Page;
import org.jsola.exception.ParamException;
import org.jsola.orm.filter.Order;
import org.jsola.permission.vo.PermissionVO;
import org.jsola.user.core.TokenUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.mapperhelper.EntityHelper;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 合同签署方签署记录
 *
 * @author JanusMix
 */
@Service("contractPartySignServiceImpl")
public class PartySignServiceImpl implements IPartySignService {

    @Autowired
    private IPartySignDAO partySignDAO;
    @Autowired
    private IContractDAO contractDAO;

    @Override
    @Transactional(value = ContractConstants.TX, rollbackFor = Exception.class)
    public PartySignVO save(PartySignAddDTO partySignAddDTO, TokenUser tokenUser) {
        // 转DO
        PartySignDO partySignDO = partySignAddDTO.to(PartySignDO.class);
        this.checkRules(partySignDO, tokenUser.getSiteId());
        // 保存
        partySignDO = save(partySignDO, tokenUser.getSiteId(), tokenUser.getUserId());
        return partySignDO.to(PartySignVO.class);
    }

    @Override
    @Transactional(value = ContractConstants.TX, rollbackFor = Exception.class)
    public List<PartySignVO> batchSave(List<PartySignAddDTO> partySignAddDTOList, TokenUser tokenUser) {
        if(CollectionUtils.isEmpty(partySignAddDTOList)) {
            return null;
        }
        List<PartySignDO> partySignDOList = partySignAddDTOList
                .parallelStream()
                .map(partySignAddDTO -> {
                    PartySignDO partySignDO = partySignAddDTO.to(PartySignDO.class);
                    partySignDO.preInsert(tokenUser.getUserId());
                    partySignDO.setSiteId(tokenUser.getSiteId());
                    this.checkRules(partySignDO, tokenUser.getSiteId());
                    return partySignDO;
                }).collect(Collectors.toList());
        partySignDAO.insertListAndSetId(partySignDOList);
        return  partySignDOList
                .parallelStream()
                .map(partySignDO -> partySignDO.to(PartySignVO.class))
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(value = ContractConstants.TX, rollbackFor = Exception.class)
    public int update(PartySignUpdateDTO partySignUpdateDTO, TokenUser tokenUser) {
        //转DO
        PartySignDO partySignDO = partySignUpdateDTO.to(PartySignDO.class);
        this.checkRules(partySignDO, tokenUser.getSiteId());
        //根据主键更新，只更新非null值
        return updateByIdSelective(partySignDO, tokenUser.getSiteId(), tokenUser.getUserId());
    }

    @Override
    @Transactional(value = ContractConstants.TX, rollbackFor = Exception.class)
    public int deleteByIds(TokenUser tokenUser, Long... partySignIds) {
        return deleteByIds(tokenUser.getSiteId(), tokenUser.getUserId(), (Object[]) partySignIds);
    }


    @Override
    public PartySignVO selectById(Long partySignId, String siteId) {
        PartySignDO partySignDO = selectDOById(partySignId, siteId);
        if (partySignDO == null) {
            return null;
        }
        return partySignDO.to(PartySignVO.class);
    }

    @Override
    public List<PartySignListVO> select(PartySignQuery partySignQuery, String siteId) {
        List<PartySignDO> partySignDOList = selectDO(partySignQuery, siteId);
        if(CollectionUtils.isEmpty(partySignDOList)) {
            return partySignDOList == null ? null : new ArrayList<>();
        }
        return partySignDOList.stream()
                .map(partySignDO -> partySignDO.to(PartySignListVO.class))
                .collect(Collectors.toList());
    }

    @Override
    public int selectCount(PartySignQuery partySignQuery, String siteId) {
        return partySignDAO.findCountByQuery(partySignQuery, siteId);
    }

    @Override
    public Page<PartySignListVO> selectPage(PartySignQuery partySignQuery, String siteId) {
        //将order参数中的propertyName改为dbName
        List<Order> orders = partySignQuery.getOrders();
        if (!CollectionUtils.isEmpty(orders)) {
            orders.forEach(order ->
                order.setProperty(EntityHelper.getEntityTable(PartySignDO.class).getPropertyMap().get(order.getProperty()).getColumn())
            );
        }
        partySignQuery.setOrders(orders);
        Page<PartySignDO> page = partySignDAO.findPageByQuery(partySignQuery, siteId);
        return page.to(PartySignListVO.class);
    }

    @Override
    public PartySignDO selectDOById(Long partySignId, String siteId) {
        return partySignDAO.findById(partySignId, siteId);
    }

    @Override
    public List<PartySignDO> selectDO(PartySignQuery partySignQuery, String siteId) {
        //将order参数中的propertyName改为dbName
        List<Order> orders = partySignQuery.getOrders();
        if (!CollectionUtils.isEmpty(orders)) {
            orders.forEach(order ->
                order.setProperty(EntityHelper.getEntityTable(PartySignDO.class).getPropertyMap().get(order.getProperty()).getColumn())
            );
        }
        partySignQuery.setOrders(orders);
        return partySignDAO.findListByQuery(partySignQuery, siteId);
    }

    @Override
    public PartySignDO selectByContractParty(Long contractId, String accountId, String siteId) {
        ParamException.notNull(contractId, "合同id不能为空");
        ParamException.notNull(accountId, "账户id不能为空");
        Example example = new Example(PartySignDO.class);
        example.and()
                .andEqualTo("siteId", siteId)
                .andEqualTo("contractId", contractId)
                .andEqualTo("accountId", accountId);
        return partySignDAO.selectOneByExample(example);
    }

    @Override
    public List<PartySignDO> selectAccountContractListWithNoSiteId(List<Long> contractIdList, String accountId) {
        ParamException.isFalse(CollectionUtils.isEmpty(contractIdList), "合同列表不能为空");
        ParamException.notNull(accountId, "账户id不能为空");
        Example example = new Example(PartySignDO.class);
        example.and()
                .andIn("contractId", contractIdList)
                .andEqualTo("accountId", accountId);
        List<PartySignDO> partySignList = partySignDAO.selectByExample(example);
        //为返回列表设置合同信息
        Example example2 = new Example(ContractDO.class);
        example2.and()
                .andIn("id", contractIdList);
        List<ContractDO> contractList = contractDAO.selectByExample(example2);
        Map<Long, ContractDO> contractMap = contractList.stream().collect(Collectors.toMap(ContractDO::getId, contract -> contract));
        for (PartySignDO partySignDO : partySignList) {
            ContractDO contractDO = contractMap.get(partySignDO.getContractId());
            if (contractDO != null) {
                partySignDO.setContractName(contractDO.getName());
                partySignDO.setContractStatus(contractDO.getStatus());
                partySignDO.setContractAppShow(contractDO.getAppIsShow());
                partySignDO.setContractPublishDate(contractDO.getPublishDate());
            }
        }
        return partySignList;
    }

    @Override
    public List<PartySignDO> selectByAccountId(String accountId, String siteId) {
        ParamException.notNull(accountId, "账户id不能为空");
        Example example = new Example(PartySignDO.class);
        example.and()
                .andEqualTo("siteId", siteId)
                .andEqualTo("accountId", accountId);
        return partySignDAO.selectByExample(example);
    }

    @Override
    public List<PartySignAccountVO> selectAccountByContractId(Long contractId, String siteId) {
        return partySignDAO.findPartySignAccount(contractId, siteId);
    }

    @Override
    public List<PartySignDO> selectByContractId(Long contractId, String siteId) {
        Example example = new Example(PartySignDO.class);
        example.and()
                .andEqualTo("siteId", siteId)
                .andEqualTo("contractId", contractId);
        return partySignDAO.selectByExample(example);
    }

    /**
     * 参数唯一校验
     */
    private void checkRules(PartySignDO partySignDO, String siteId) {
        Example example1 = new Example(PartySignDO.class);
        List<String> fieldValue1 = new ArrayList<>();
        fieldValue1.add(SafeKit.getString(partySignDO.getAccountId()));
        example1.and().andEqualTo("accountId", partySignDO.getAccountId());
        fieldValue1.add(SafeKit.getString(partySignDO.getContractId()));
        example1.and().andEqualTo("contractId", partySignDO.getContractId());
        //如果是更新，判断更新前后的唯一索引有没有产生变化
        if (partySignDO.getId() != null) {
            PartySignDO existDO = partySignDAO.selectOneByExample(example1);
            if (existDO != null && !existDO.getId().equals(partySignDO.getId())) {
                throw new ParamException("账户id 合同id [" + String.join(",", fieldValue1) + "]值重复");
            }
        } else {
            if (partySignDAO.selectCountByExample(example1) > 0) {
                throw new ParamException("账户id 合同id [" + String.join(",", fieldValue1) + "]值重复");
            }
        }
    }

    @Override
    @Transactional(value = ContractConstants.TX, rollbackFor = Exception.class)
    public void deleteByContractId(Long contractId, TokenUser tokenUser) {
        Example example = new Example(PartySignDO.class);
        example.and()
                .andEqualTo("contractId", contractId)
                .andEqualTo("siteId", tokenUser.getSiteId());
        partySignDAO.deleteByExample(example);
    }

    @Override
    public void deleteByContractIds(List<Long> contractIds, TokenUser tokenUser) {
        if (CollectionUtils.isEmpty(contractIds)) {
            return;
        }
        Example example = new Example(PartySignDO.class);
        example.and()
                .andIn("contractId", contractIds)
                .andEqualTo("siteId", tokenUser.getSiteId());
        partySignDAO.deleteByExample(example);
    }

    @Override
    public List<PartySignListVO> listAllByAccountId(String accountId) {
        Example example = new Example(PartySignDO.class);
        example.and()
                .andEqualTo("accountId", accountId);
        List<PartySignDO> partySignDOList = partySignDAO.selectByExample(example);
        if (CollectionUtils.isEmpty(partySignDOList)) {
            return null;
        }
        return partySignDOList.stream().map(partySignDO -> partySignDO.to(PartySignListVO.class)).collect(Collectors.toList());
    }

    @Override
    public void setContractInfo(PartySignListVO partySignListVO) {
        // 查询合同
        Long contractId = partySignListVO.getContractId();
        if (StrKit.isNotEmpty(contractId)) {
            Example example = new Example(ContractDO.class);
            example.and()
                    .andEqualTo("id", contractId);
            ContractDO contractDO = contractDAO.selectOneByExample(example);
            if (!Objects.isNull(contractDO)) {
                partySignListVO.setContractAppShow(contractDO.getAppIsShow());
                partySignListVO.setContractName(contractDO.getName());
                partySignListVO.setContractPublishDate(contractDO.getPublishDate());
                partySignListVO.setContractStatus(contractDO.getStatus());
            }
        }
    }

}




